﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Roton2.MemoryEmulation
{
    /// <summary>
    /// Representation of a void pointer, to be used with MemoryEmulation.Block.
    /// </summary>
    public class Reference
    {
        static Encoding enc = Encoding.GetEncoding(437);

        Block block;
        int offset;

        /// <summary>
        /// Assign a pointer to a block of memory at the specified offset.
        /// </summary>
        public Reference(Block block, int offset)
        {
            this.block = block;
            this.offset = offset;
        }

        /// <summary>
        /// Get or set a byte at the specified index from the pointer's base offset.
        /// </summary>
        public byte this[int index]
        {
            get
            {
                return block[index];
            }
            set
            {
                block[index] = value;
            }
        }

        /// <summary>
        /// Get or set an 8-bit value at the pointer's base offset.
        /// </summary>
        public byte Byte
        {
            get
            {
                return block[0];
            }
            set
            {
                block[0] = value;
            }
        }

        /// <summary>
        /// Get or set a 16-bit value at the pointer's base offset.
        /// </summary>
        public int Int16
        {
            get
            {
                Int32 result;
                result = block[1];
                result <<= 8;
                result |= block[0];
                result <<= 16;
                result >>= 16;
                return result;
            }
            set
            {
                block[0] = (byte)(value & 0xFF);
                value >>= 8;
                block[1] = (byte)(value & 0xFF);
            }
        }

        /// <summary>
        /// Get or set a 32-bit value at the pointer's base offset.
        /// </summary>
        public int Int32
        {
            get
            {
                Int32 result;
                result = block[3];
                result <<= 8;
                result |= block[2];
                result <<= 8;
                result |= block[1];
                result <<= 8;
                result |= block[0];
                return result;
            }
            set
            {
                block[0] = (byte)(value & 0xFF);
                value >>= 8;
                block[1] = (byte)(value & 0xFF);
                value >>= 8;
                block[2] = (byte)(value & 0xFF);
                value >>= 8;
                block[3] = (byte)(value & 0xFF);
            }
        }

        /// <summary>
        /// Get or set the base offset for this pointer.
        /// </summary>
        public int Offset
        {
            get
            {
                return offset;
            }
            set
            {
                this.offset = value;
            }
        }

        /// <summary>
        /// Get or set the pascal-style string at the pointer's base offset.
        /// </summary>
        public string PString
        {
            get
            {
                int length = block[0];
                List<byte> result = new List<byte>();

                for (int index = 1; index <= length; index++)
                    result.Add(block[index]);

                return enc.GetString(result.ToArray());
            }
            set
            {
                byte[] bytes = enc.GetBytes(value);
                byte length = (byte)(bytes.Length & 0xFF);

                for (int index = 0; index < length; index++)
                    block[index + 1] = bytes[index];
            }
        }
    }
}
